package com.wish.group05.base.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.wish.group05.base.dto.CheckBatchConfirmRequestDto;
import com.wish.group05.base.dto.CwCheckBatchDetailRequestDto;
import com.wish.group05.base.dto.CwCheckBatchDetailResponseDto;
import com.wish.group05.base.dto.RequestForDownLoadBills;
import com.wish.group05.base.entity.*;
import com.wish.group05.base.mapper.CwCheckBatchDetailMapper;
import com.wish.group05.base.mapper.CwCheckBatchMapper;
import com.wish.group05.base.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wish.group05.common.security.service.TokenService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * <p>
 * 对账批次表 服务实现类
 * </p>
 *
 * @author houzehui
 * @since 2022-05-23
 */
@Slf4j
@Service
public class CwCheckBatchServiceImpl extends ServiceImpl<CwCheckBatchMapper, CwCheckBatch> implements ICwCheckBatchService {

    @Autowired
    ICwCheckBatchDetailService cwCheckBatchDetailService;
    @Autowired
    ICwPayOrderService cwPayOrderService;
    @Autowired
    ICwPayOrderDetailService cwPayOrderDetailService;
    @Autowired
    TokenService tokenService;
    @Autowired
    ICwClearingService cwClearingService;
    @Autowired
    CwCheckBatchDetailMapper cwCheckBatchDetailMapper;
    @Autowired
    ICwLklCheckFileService lklCheckFileService;

    /**
     * 对账确认
     * @param checkBatchConfirmRequestDto
     */
    @Override
    public void checkBatchConfirm(CheckBatchConfirmRequestDto checkBatchConfirmRequestDto) {

        log.info("checkBatchConfir对账确认处理 Start...");

        // 对账确认时间
        Date confirmDate = new Date();

        // 查询批次信息

        CwCheckBatch batchInfo = this.selectCheckBatchByBatchNo(checkBatchConfirmRequestDto.getBatchNo());

        if (batchInfo == null) {
            log.warn("----未查到该批次信息，对账确认失败.");
            throw new RuntimeException("未查到该批次信息，对账确认失败。");
        }else {
            // 批次状态
            // 取消或者未完成的时候
            if (batchInfo.getCompleteState() == 3) {
                log.warn("----该批次信息已取消，对账确认失败.");
                throw new RuntimeException("该批次信息已取消，对账确认失败。");
            } else if (batchInfo.getCompleteState() == 2) {
                log.warn("----该批次信息未完成，对账确认失败.");
                throw new RuntimeException("该批次信息未完成，对账确认失败。");
            }else {
                if (batchInfo.getConfirmDate() != null) {
                    log.warn("----该批次信息已是对账确认状态，对账确认失败.");
                    throw new RuntimeException("该批次信息已是对账确认状态，对账确认失败");
                }
            }
        }

        // 查询该批次对应的明细数据
        CwCheckBatchDetail batchDetailOption = new CwCheckBatchDetail();
        batchDetailOption.setBatchNo(checkBatchConfirmRequestDto.getBatchNo());
        batchDetailOption.setDelFlg(false);
        QueryWrapper<CwCheckBatchDetail> wrapper = new QueryWrapper<>(batchDetailOption);
        List<CwCheckBatchDetail> batchDetailList = cwCheckBatchDetailService.list(wrapper);

        if (batchDetailList == null || batchDetailList.size() == 0) {
            log.warn("----该批次对应的明细数据无.");
            throw new RuntimeException("该批次无对账明细数据");
        }else {
            // 检查每条明细的差错处理状态
            for (CwCheckBatchDetail batchDetailItem : batchDetailList) {
                if (batchDetailItem.getHasDiff() && batchDetailItem.getProcessState() == 1) {
                    log.info("存在未处理的差错，对账确认失败。");
                    throw new RuntimeException("存在未处理的差错，对账确认失败。");
                }
            }
        }

        log.info("----该批次对应的明细数据共{}条。", batchDetailList.size());

        // 循环对账明细，将无差错的或者要结算的入金账单，插入到待结算表中，等待结算审核（线上交易部分）
        for (CwCheckBatchDetail batchDetailItem : batchDetailList) {
            log.info("--------当前处理批次明细数据（{}）。", JSON.toJSONString(batchDetailItem));

            if (batchDetailItem.getCanClearingAmount() != null      // 有商户可结算金额
                    && BigDecimal.ZERO.compareTo(batchDetailItem.getCanClearingAmount()) < 0 // 商户可结算金额 > 0
                    && (!batchDetailItem.getHasDiff() || (batchDetailItem.getHasDiff()  // 无差错
                    && batchDetailItem.getProcessState() == 2))) {  // 有差错，处理状态是要结算
                // 查询对应的系统支付订单信息
                // 对账明细中的支付订单号（交易流水号是拉卡拉同平台的号用/拼接的）
                String dispPayOrderNo = batchDetailItem.getPayOrderNo();

                if (StringUtils.isBlank(dispPayOrderNo)) {
                    log.error("--------当前处理的批次明细中没有支付订单号，该条明细处理跳过。");
                    continue;
                }

                // 拉卡拉订单号在左边，平台在右边
                String[] dispOrderNoArray = dispPayOrderNo.split("/");

                if (dispOrderNoArray == null || dispOrderNoArray.length == 0) {
                    log.error("--------当前处理的批次明细中没有支付订单号，该条明细处理跳过。");
                    continue;
                }

                // 先使用平台支付订单，没有的时候，使用拉卡拉对账的支付订单
                String orderNo =  dispOrderNoArray.length == 1 ? dispOrderNoArray[0] : dispOrderNoArray[1];

                CwPayOrder payOrder = cwPayOrderService.selectPayOrderByOrderNo(orderNo);

                //结算管理
                CwClearing cwClearing = new CwClearing();
                // 商户信息(商户ID, 商户名称)
                setBusinessInfoInClearing(cwClearing,payOrder);

                // 对账年月日(yyyymmdd)
                cwClearing.setCheckDay(batchDetailItem.getCheckDay());
                // 结算的对账批次ID
                cwClearing.setCheckBatchId(batchDetailItem.getBatchId());
                // 结算的对账批次号（yyyymmdd001）
                cwClearing.setCheckBatchNo(batchDetailItem.getBatchNo());
                // 结算的对账批次明细ID
                cwClearing.setCheckBatchDetailId(batchDetailItem.getId());

                // 交易流水号，支付订单的支付订单号
                cwClearing.setPayOrderNo(orderNo);

                // 渠道名称(拉卡拉账单类型) 1:代付（提现），2：快捷，3：微信，4：支付宝
                cwClearing.setBillType(batchInfo.getBillType());

                // 对账确认时间
                cwClearing.setCheckConfirmDate(confirmDate);

                if (payOrder.getCanClearingAmount() != null) {
                    cwClearing.setAmount(payOrder.getCanClearingAmount());
                }

                // 交易日期（对账明细里面的交易日期，也即渠道支付日期）
                cwClearing.setTradeDateZf(payOrder.getTradeDateZf());

                // 结算确认状态（未确认）
                cwClearing.setClearingConfirmState(1);

                // 结算确认人    (结算时设置)
                // 结算确认时间 (结算时设置)

                // 创建人/时间， 更新人/时间
                cwClearing.setCreateUserid(tokenService.getLoginUser().getUserid());
                cwClearing.setCreateTime(new Date());
                cwClearing.setUpdateUserid(tokenService.getLoginUser().getUserid());
                cwClearing.setUpdateTime(new Date());

                // 创建结算明细记录
                cwClearingService.saveOrUpdate(cwClearing);

                log.info("------------创建结算明细记录({})。", JSON.toJSONString(cwClearing));

                //  **************** 2、更新需要结算的支付订单的状态
                CwPayOrder payOrderForUpdate = new CwPayOrder();
                payOrderForUpdate.setId(payOrder.getId());
                // 对账状态：2=已对账----->   3=待结算
                payOrderForUpdate.setDzState(3);
                payOrderForUpdate.setUpdateUserid(tokenService.getLoginUser().getUserid());
                payOrderForUpdate.setUpdateTime(new Date());

                // 更新支付订单状态
                cwPayOrderService.saveOrUpdate(payOrderForUpdate);

                log.info("------------更新支付订单状态({})。", JSON.toJSONString(payOrderForUpdate));

            }else {
                log.info("------------没有商户可结算金额，不用结算。");
            }
        }

        // **************** 3、更新对账批次明细和对账批次表对账确认时间
        // 对账批次明细
        checkBatchConfirmRequestDto.setLoginUserId(tokenService.getLoginUser().getUserid());
        cwCheckBatchDetailMapper.updateConfirmDate(checkBatchConfirmRequestDto);

        log.info("--------更新对账批次明细完成。");

        // 对账批次
        CwCheckBatch batchInfoForUpdate = new CwCheckBatch();
        batchInfoForUpdate.setId(batchInfo.getId());
        batchInfoForUpdate.setConfirmDate(confirmDate);
        batchInfoForUpdate.setUpdateUserid(tokenService.getLoginUser().getUserid());
        batchInfoForUpdate.setUpdateTime(new Date());

        saveOrUpdate(batchInfoForUpdate);
        log.info("--------更新对账批次表完成。");
        log.info("checkBatchConfir对账确认处理 End.");
    }

    /**
     * 对账处理
     * @param checkBatchConfirmRequestDto
     * @return
     */
    @Override
    public void checkBillBatch(CheckBatchConfirmRequestDto checkBatchConfirmRequestDto) {
        log.info("checkBillBatch对账处理 Start...");

        //手动对账
        if (checkBatchConfirmRequestDto.getBatchType() == 3) {
            log.info("手动执行对账开始...");
            // 手动对账的时候，账期年月日根据选择的批次来取得
            // 1、查询旧批次信息
            CwCheckBatch oldBatch = selectCheckBatchByBatchNo(checkBatchConfirmRequestDto.getBatchNo());

            if (oldBatch == null) {
                log.error("----旧批次查询结果无(批次号：{})。", checkBatchConfirmRequestDto.getBatchNo());
                throw new RuntimeException("旧批次查询结果无，重新对账处理失败。");
            }

            // 旧批次状态check
            // 取消状态和对账确认状态，不允许重新对账
            //取消状态
            if (oldBatch.getCompleteState() == 3) {
                log.warn("----指定旧批次已经被取消，不能进行对账处理(批次号：{})。", checkBatchConfirmRequestDto.getBatchNo());
                throw new RuntimeException("指定旧批次已经被取消，不能进行对账处理。");
            }
            //对账确认时间不为空，说明已对账
            if (oldBatch.getConfirmDate() != null) {
                log.warn("----指定批次已经对账确认，不能进行对账处理(批次号：{})。", checkBatchConfirmRequestDto.getBatchNo());
                throw new RuntimeException("指定批次已经对账确认，不能进行对账处理。");
            }

            log.info("----1、旧批次查询结果（{}）", JSON.toJSONString(oldBatch));


            // 2、从拉卡拉重新下载并保存账单
            RequestForDownLoadBills downLoadRequest = new RequestForDownLoadBills();
            downLoadRequest.setBillDay(oldBatch.getBillDay());
            //渠道名称(账单类型)
            downLoadRequest.setBillType(oldBatch.getBillType().toString());
            String downloadBatch = lklCheckFileService.downloadBills(downLoadRequest);

        }

    }

    /**
     * 对账确认的时候，取得并设置对应流水的商户信息
     * @param cwClearing
     * @param payOrder
     */
    private void setBusinessInfoInClearing(CwClearing cwClearing, CwPayOrder payOrder) {
        log.info("setBusinessInfoInClearing商户信息设置处理 Start...");

        if (payOrder == null) {
            return;
        }

        //  查询该笔支付订单对应的业务订单，然后根据业务订单确定商户
        CwPayOrderDetail selectOption = new CwPayOrderDetail();
        // 支付订单ID
        selectOption.setPayOrderId(payOrder.getId());
        selectOption.setDelFlg(false);
        QueryWrapper<CwPayOrderDetail> wrapper = new QueryWrapper<>(selectOption);

        List<CwPayOrderDetail> orderDetailList = cwPayOrderDetailService.list(wrapper);

        if (orderDetailList == null || orderDetailList.size() == 0)  {
            log.info("----支付订单明细数据查询无.");
            log.info("setBusinessInfoInClearing商户信息设置处理 End.");
            return;
        }

        for (CwPayOrderDetail orderDetail : orderDetailList) {
            // 目前业务中，入金的业务包括企业充值和企业收款（TODO暂不考虑金融相关业务）

            if (orderDetail.getBusinessOrderType() == 1 || orderDetail.getBusinessOrderType() == 3) {
                // 商户ID设置
                cwClearing.setBusinessId(orderDetail.getBusinessId());
                // 商户名称设置
                cwClearing.setBusinessName(orderDetail.getBusinessName());

                log.info("----商户信息设置成功。");

                // 暂时不考虑一笔流水里面对应多个商家的情况
                break;
            }

            log.info("setBusinessInfoInClearing商户信息设置处理 End.");
        }


    }

    /*
     * 根据对账批次号（不是ID）查询对账批次信息
     */
    private CwCheckBatch selectCheckBatchByBatchNo(String batchNo) {
        log.info("selectCheckBatchByBatchNo处理 Start...");

        CwCheckBatch cwCheckBatch = new CwCheckBatch();
        cwCheckBatch.setBatchNo(batchNo);
        cwCheckBatch.setDelFlg(false);
        QueryWrapper<CwCheckBatch> wrapper = new QueryWrapper<>(cwCheckBatch);

        CwCheckBatch checkBatch = getOne(wrapper);

        log.info("selectCheckBatchByBatchNo处理 End.");

        return checkBatch;

    }
}
